package com.neuronrobotics.opengl.scene;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import java.util.Arrays;

import com.neuronrobotics.replicator.gui.stl.GeneralTransform3D.MatrixOrder;

import android.opengl.GLES20;
import android.opengl.Matrix;

public class ArrayShapeNode extends ShapeNode {
	
	//TODO users shouldn't be setting this up?

	private FloatBuffer vertexBuffer = null;
	private FloatBuffer normalBuffer = null;
		
	//Data for vertex and normal data for each facet
	protected float coordinates[];
	protected float normals[];
	
	protected int vertexCount; //Amount of vertices
	protected int vertexStride;// bytes per vertex
		
	private boolean isHighlighted = false;
	
	private boolean initialized = false;
	
	protected int drawStart;
	protected int drawEnd;
			
	public ArrayShapeNode(GLHandles handles,float[] coords, float[] norms, int drawType){
		super();
		this.theHandles = handles;
		this.vertexStride = 3*4;
		this.vertexCount = coords.length/3;		
		this.drawStart = 0;
		this.drawEnd = vertexCount;
		this.coordinates = Arrays.copyOf(coords,coords.length);
		this.normals = Arrays.copyOf(norms, norms.length);
		this.drawArrayType = drawType;
		this.modelTransform = new float[16];
		Matrix.setIdentityM(modelTransform, 0);
		isVisible=true;
	}
		
	protected final void initialize(){
		
		//set up the vertex buffer
		ByteBuffer bb = ByteBuffer.allocateDirect(coordinates.length * 4);
		bb.order(ByteOrder.nativeOrder());
		vertexBuffer = bb.asFloatBuffer();
		vertexBuffer.put(coordinates);
		vertexBuffer.position(0);
				
		//Set up normal buffer
		ByteBuffer tempNBuff = ByteBuffer.allocateDirect(normals.length* 4);
        tempNBuff.order(ByteOrder.nativeOrder()).asFloatBuffer();							
		normalBuffer = tempNBuff.asFloatBuffer();
		normalBuffer.put(normals);
		normalBuffer.position(0);		

		initialized = true;
	}

	public boolean setTransform(float[] newTransform, MatrixOrder matOrder) {
		if(modelTransform==null) modelTransform = new float[16];
		if (newTransform.length < 16)
			return false;
		int len = 16;
		for (int i = 0; i < len; i++)
			this.modelTransform[i] = newTransform[i];
		if(matOrder!=MatrixOrder.COLUMN_MAJOR) MatrixOrder.convertOrder(newTransform, 0, newTransform,0);
		return true;
	}
	
	public void setHighlighted(boolean b){
		isHighlighted = b;
	}
	
	public boolean isHighlighted(){
		return isHighlighted;
	}

	@Override
	protected void draw(float[] viewMatrix, float[] projMatrix) {
	
		if (!isVisible)
			return;
		
		if (!initialized) {
			initialize();
		}

		// Add program to OpenGL environment
		GLES20.glUseProgram(theHandles.mProgram);

		// Enable a handle to the triangle vertices
		GLES20.glEnableVertexAttribArray(theHandles.mPositionHandle);

		// Prepare the triangle coordinate data
		GLES20.glVertexAttribPointer(theHandles.mPositionHandle,
				coordsPerVertex, GLES20.GL_FLOAT, false, vertexStride,
				vertexBuffer);

		// Prepare normal data
		GLES20.glEnableVertexAttribArray(theHandles.mNormalHandle);

		GLES20.glVertexAttribPointer(theHandles.mNormalHandle, coordsPerVertex,
				GLES20.GL_FLOAT, false, vertexStride, normalBuffer);

		float colOffset = (isHighlighted) ? .2f : 0;

		// Setting correct color
		GLES20.glUniform4f(theHandles.mColorHandle, color[0] + colOffset,
				color[1] + colOffset, color[2] + colOffset, color[3]);

		// set up models view/model/projection matrices
		GLES20.glUniformMatrix4fv(theHandles.mMMatrixHandle, 1, false,
				this.modelTransform, 0);
		GLES20.glUniformMatrix4fv(theHandles.mVMatrixHandle, 1, false,
				viewMatrix, 0);
		GLES20.glUniformMatrix4fv(theHandles.mPMatrixHandle, 1, false,
				projMatrix, 0);

		//Set lights on or off
		GLES20.glUniform1i(theHandles.lightsOnHandle, lightsOn?1:0);		
		
		// Set light position
		GLES20.glUniform3f(theHandles.lightPosHandle, lightPosition[0],
				lightPosition[1], lightPosition[2]);

		// Draw the object
		GLES20.glDrawArrays(drawArrayType, drawStart, drawEnd); 
		
		// Disable vertex array
		GLES20.glDisableVertexAttribArray(theHandles.mPositionHandle);
		
			
	}


}
